package logic.ships.hunter;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import settings.GraphicSettings;

import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.CullState.Face;
import com.jme.system.DisplaySystem;
import com.jmex.effects.particles.ParticleFactory;
import com.jmex.effects.particles.ParticleMesh;

import factories.ParticleRemoveController;
import fileHandling.TextureLoader;

import logic.nodes.lod.blocks.LeafBlock;
import logic.weapons.projectileWeapons.heatSeeker.HeatSeeker;
import main.InitGame;

public class CounterMeasure extends Node {
	
	private static final long serialVersionUID = 1L;
	
	private static BlendState blendState;
	private static TextureState textureState;
	private static ZBufferState zBufferState;
	private static CullState cullState;
	
	public static final float RELOAD_TIME = 2f;
	
	private Hunter hunter;
	private float reloadTime;
	private Random rand;
	private List<HeatSeeker> heatSeekers, copy;
	private CounterMeasureController cmController;
	
	public CounterMeasure(Hunter hunter) {
		super("Counter Measure of " + hunter.getName());
		this.hunter = hunter;
		
		heatSeekers = new ArrayList<HeatSeeker>();
		copy = new ArrayList<HeatSeeker>();
		
		cmController = new CounterMeasureController(this);
		
		if(blendState == null) changeGraphicSettings();
		
		rand = new Random();
	}
	
	public static void changeGraphicSettings() {
		Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
		
		blendState = renderer.createBlendState();
		blendState.setBlendEnabled(true);
		blendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
		blendState.setDestinationFunction(BlendState.DestinationFunction.One);
		blendState.setTestEnabled(true);
		blendState.setTestFunction(BlendState.TestFunction.GreaterThan);
		
		String qual = GraphicSettings.get().getTextureQuality();
		String trailPath = "data/textures/effects/particles/roundParticle/" + qual + ".png";
		textureState = TextureLoader.getTextureState(trailPath);
		
		zBufferState = renderer.createZBufferState();
		zBufferState.setWritable(false);
		zBufferState.setEnabled(true);
		
		cullState = renderer.createCullState();
		cullState.setCullFace(Face.None);
		cullState.setEnabled(true);
	}
	
	public void addHeatSeeker(HeatSeeker heatSeeker) {
		heatSeekers.add(heatSeeker);
	}
	
	public void removeHeatSeeker(HeatSeeker heatSeeker) {
		heatSeekers.remove(heatSeeker);
	}
	
	public void use() { use(false); }
	
	public void use(boolean dummy) {
		if(isReloading() || heatSeekers.isEmpty()) return;
		
		if(!dummy && !InitGame.get().isServer()) {
			InitGame.get().getClientState().handleCMUse(hunter.getPilot());
			return;
		}
		
		ParticleMesh particles = addExplosion(ColorRGBA.white);
		if(particles == null) return;
		
		if(!dummy) {
			assert(InitGame.get().isServer());
			int maxTargets = particles.getQuantity() + 1;
			int targetIndex = rand.nextInt(maxTargets);
			
			if(targetIndex < maxTargets - 1) {
				copy.addAll(heatSeekers);
				for(HeatSeeker heatSeeker : copy) {
					if(heatSeeker != null) heatSeeker.changeTarget(particles);
				}
				heatSeekers.clear();
				copy.clear();
			}
			
			InitGame.get().getServerState().sendCMUseMessage(hunter.getPilot().getID());
		}
		
		addController(cmController);
		
		changeReloadTime(RELOAD_TIME);
	}
	
	protected ParticleMesh addExplosion(ColorRGBA color) {
		ParticleMesh mesh = getCMParticles(color);
		mesh.getLocalTranslation().set(hunter.getLocalTranslation());
		
		Node parent = hunter.getParent();
		if(parent != null && LeafBlock.isVisible(hunter.getLocalTranslation(), hunter.getIngameState())) {
			parent.attachChild(mesh);
			mesh.addController(new ParticleRemoveController(mesh));
		} else if(parent == null) return null;
		
		mesh.updateGeometricState(0f, true);
		mesh.forceRespawn();
		return mesh;
	}
	
	private ParticleMesh getCMParticles(ColorRGBA color) {
		int amount = hunter.getHunterProperties().getCMEfficiency();
		ParticleMesh particles = ParticleFactory.buildParticles("countermeasures", amount);
		particles.setEmissionDirection(Vector3f.UNIT_Y.clone());
		
		particles.setMaximumAngle(FastMath.PI);
		particles.setMinimumAngle(0f);
		particles.getParticleController().setSpeed(0.1f);
		particles.setMinimumLifeTime(100f);
		particles.setMaximumLifeTime(200f);
		particles.setStartSize(1f);
		particles.setEndSize(0.8f);
		particles.getParticleController().setControlFlow(false);
		particles.getParticleController().setRepeatType(Controller.RT_CLAMP);
		particles.warmUp(200);
		particles.setInitialVelocity(0.15f);
		particles.setStartColor(color);
		particles.setEndColor(color);
		
		particles.setCullHint(CullHint.Never);
		
		particles.setRenderState(textureState);
		particles.setRenderState(blendState);
		particles.setRenderState(zBufferState);
		particles.setRenderState(cullState);
		particles.updateRenderState();
		
		return particles;
	}
	
	private void changeReloadTime(float newValue) {
		if(reloadTime == newValue) return;
		reloadTime = newValue;
				
		hunter.updateCMLoad(newValue);
		
		if(!isReloading()) removeController(cmController);
	}
	
	public boolean isReloading() { return reloadTime > 0f; }
	
	public void reload(float time) {
		float amount = time * hunter.getHunterProperties().getCMReloadTime();
		if(reloadTime - amount < 0f) amount = reloadTime;
		changeReloadTime(reloadTime - amount);
	}
	
	public float getReloadTime() { return reloadTime; }
	
	public List<HeatSeeker> getHeatSeekers() { return heatSeekers; }
	
	public void restore() { changeReloadTime(0f); }
}